<template>
	<view>
		<view ref="uni-rate" class="uni-rate">
			<view class="uni-rate__icon" :class="{'uni-cursor-not-allowed': disabled}"
				:style="{ 'margin-right': marginNumber + 'px' }" v-for="(star, index) in stars" :key="index"
				@touchstart.stop="touchstart" @touchmove.stop="touchmove" @mousedown.stop="mousedown"
				@mousemove.stop="mousemove" @mouseleave="mouseleave">
				<uni-icons :color="color" :size="size" :type="isFill ? 'star-filled' : 'star'" />
				<!-- #ifdef APP-NVUE -->
				<view :style="{ width: star.activeWitch.replace('%','')*size/100+'px'}" class="uni-rate__icon-on">
					<uni-icons style="text-align: left;" :color="disabled?'#ccc':activeColor" :size="size"
						type="star-filled" />
				</view>
				<!-- #endif -->
				<!-- #ifndef APP-NVUE -->
				<view :style="{ width: star.activeWitch}" class="uni-rate__icon-on">
					<uni-icons :color="disabled?disabledColor:activeColor" :size="size" type="star-filled" />
				</view>
				<!-- #endif -->
			</view>
		</view>
	</view>
</template>

<script>
// #ifdef APP-NVUE
const dom = uni.requireNativePlugin('dom')
// #endif
/**
	 * Rate 评分
	 * @description 评分组件
	 * @tutorial https://ext.dcloud.net.cn/plugin?id=33
	 * @property {Boolean} 	isFill = [true|false] 		星星的类型，是否为实心类型, 默认为实心
	 * @property {String} 	color 						未选中状态的星星颜色，默认为 "#ececec"
	 * @property {String} 	activeColor 				选中状态的星星颜色，默认为 "#ffca3e"
	 * @property {String} 	disabledColor 				禁用状态的星星颜色，默认为 "#c0c0c0"
	 * @property {Number} 	size 						星星的大小
	 * @property {Number} 	value/v-model 				当前评分
	 * @property {Number} 	max 						最大评分评分数量，目前一分一颗星
	 * @property {Number} 	margin 						星星的间距，单位 px
	 * @property {Boolean} 	disabled = [true|false] 	是否为禁用状态，默认为 false
	 * @property {Boolean} 	readonly = [true|false] 	是否为只读状态，默认为 false
	 * @property {Boolean} 	allowHalf = [true|false] 	是否实现半星，默认为 false
	 * @property {Boolean} 	touchable = [true|false] 	是否支持滑动手势，默认为 true
	 * @event {Function} change 						uniRate 的 value 改变时触发事件，e={value:Number}
	 */

export default {
  name: 'UniRate',
  props: {
    isFill: {
      // 星星的类型，是否镂空
      type: [Boolean, String],
      default: true
    },
    color: {
      // 星星未选中的颜色
      type: String,
      default: '#ececec'
    },
    activeColor: {
      // 星星选中状态颜色
      type: String,
      default: '#ffca3e'
    },
    disabledColor: {
      // 星星禁用状态颜色
      type: String,
      default: '#c0c0c0'
    },
    size: {
      // 星星的大小
      type: [Number, String],
      default: 24
    },
    value: {
      // 当前评分
      type: [Number, String],
      default: 0
    },
    modelValue: {
      // 当前评分
      type: [Number, String],
      default: 0
    },
    max: {
      // 最大评分
      type: [Number, String],
      default: 5
    },
    margin: {
      // 星星的间距
      type: [Number, String],
      default: 0
    },
    disabled: {
      // 是否可点击
      type: [Boolean, String],
      default: false
    },
    readonly: {
      // 是否只读
      type: [Boolean, String],
      default: false
    },
    allowHalf: {
      // 是否显示半星
      type: [Boolean, String],
      default: false
    },
    touchable: {
      // 是否支持滑动手势
      type: [Boolean, String],
      default: true
    }
  },
  data () {
    return {
      valueSync: '',
      userMouseFristMove: true,
      userRated: false,
      userLastRate: 1
    }
  },
  watch: {
    value (newVal) {
      this.valueSync = Number(newVal)
    },
    modelValue (newVal) {
      this.valueSync = Number(newVal)
    }
  },
  computed: {
    stars () {
      const value = this.valueSync ? this.valueSync : 0
      const starList = []
      const floorValue = Math.floor(value)
      const ceilValue = Math.ceil(value)
      for (let i = 0; i < this.max; i++) {
        if (floorValue > i) {
          starList.push({
            activeWitch: '100%'
          })
        } else if (ceilValue - 1 === i) {
          starList.push({
            activeWitch: (value - floorValue) * 100 + '%'
          })
        } else {
          starList.push({
            activeWitch: '0'
          })
        }
      }
      return starList
    },

    marginNumber () {
      return Number(this.margin)
    }
  },
  created () {
    this.valueSync = Number(this.value || this.modelValue)
    this._rateBoxLeft = 0
    this._oldValue = null
  },
  mounted () {
    setTimeout(() => {
      this._getSize()
    }, 100)
    // #ifdef H5
    this.PC = this.IsPC()
    // #endif
  },
  methods: {
    touchstart (e) {
      // #ifdef H5
      if (this.IsPC()) return
      // #endif
      if (this.readonly || this.disabled) return
      const {
        clientX,
        screenX
      } = e.changedTouches[0]
      // TODO 做一下兼容，只有 Nvue 下才有 screenX，其他平台式 clientX
      this._getRateCount(clientX || screenX)
    },
    touchmove (e) {
      // #ifdef H5
      if (this.IsPC()) return
      // #endif
      if (this.readonly || this.disabled || !this.touchable) return
      const {
        clientX,
        screenX
      } = e.changedTouches[0]
      this._getRateCount(clientX || screenX)
    },

    /**
			 * 兼容 PC @tian
			 */

    mousedown (e) {
      // #ifdef H5
      if (!this.IsPC()) return
      if (this.readonly || this.disabled) return
      const {
        clientX
      } = e
      this.userLastRate = this.valueSync
      this._getRateCount(clientX)
      this.userRated = true
      // #endif
    },
    mousemove (e) {
      // #ifdef H5
      if (!this.IsPC()) return
      if (this.userRated) return
      if (this.userMouseFristMove) {
        console.log('---mousemove----', this.valueSync)
        this.userLastRate = this.valueSync
        this.userMouseFristMove = false
      }
      if (this.readonly || this.disabled || !this.touchable) return
      const {
        clientX
      } = e
      this._getRateCount(clientX)
      // #endif
    },
    mouseleave (e) {
      // #ifdef H5
      if (!this.IsPC()) return
      if (this.readonly || this.disabled || !this.touchable) return
      if (this.userRated) {
        this.userRated = false
        return
      }
      this.valueSync = this.userLastRate
      // #endif
    },
    // #ifdef H5
    IsPC () {
      const userAgentInfo = navigator.userAgent
      const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod']
      let flag = true
      for (let v = 0; v < Agents.length - 1; v++) {
        if (userAgentInfo.indexOf(Agents[v]) > 0) {
          flag = false
          break
        }
      }
      return flag
    },
    // #endif

    /**
			 * 获取星星个数
			 */
    _getRateCount (clientX) {
      this._getSize()
      const size = Number(this.size)
      if (isNaN(size)) {
        return new Error('size 属性只能设置为数字')
      }
      const rateMoveRange = clientX - this._rateBoxLeft
      let index = parseInt(rateMoveRange / (size + this.marginNumber))
      index = index < 0 ? 0 : index
      index = index > this.max ? this.max : index
      const range = parseInt(rateMoveRange - (size + this.marginNumber) * index)
      let value = 0
      if (this._oldValue === index && !this.PC) return
      this._oldValue = index
      if (this.allowHalf) {
        if (range > (size / 2)) {
          value = index + 1
        } else {
          value = index + 0.5
        }
      } else {
        value = index + 1
      }

      value = Math.max(0.5, Math.min(value, this.max))
      this.valueSync = value
      this._onChange()
    },

    /**
			 * 触发动态修改
			 */
    _onChange () {
      this.$emit('input', this.valueSync)
      this.$emit('update:modelValue', this.valueSync)
      this.$emit('change', {
        value: this.valueSync
      })
    },
    /**
			 * 获取星星距离屏幕左侧距离
			 */
    _getSize () {
      // #ifndef APP-NVUE
      uni.createSelectorQuery()
        .in(this)
        .select('.uni-rate')
        .boundingClientRect()
        .exec(ret => {
          if (ret) {
            this._rateBoxLeft = ret[0].left
          }
        })
      // #endif
      // #ifdef APP-NVUE
      dom.getComponentRect(this.$refs['uni-rate'], (ret) => {
        const size = ret.size
        if (size) {
          this._rateBoxLeft = size.left
        }
      })
      // #endif
    }
  }
}
</script>

<style lang="scss">
	.uni-rate {
		/* #ifndef APP-NVUE */
		display: flex;
		/* #endif */
		line-height: 1;
		font-size: 0;
		flex-direction: row;
		/* #ifdef H5 */
		cursor: pointer;
		/* #endif */
	}

	.uni-rate__icon {
		position: relative;
		line-height: 1;
		font-size: 0;
	}

	.uni-rate__icon-on {
		overflow: hidden;
		position: absolute;
		top: 0;
		left: 0;
		line-height: 1;
		text-align: left;
	}

	.uni-cursor-not-allowed {
		/* #ifdef H5 */
		cursor: not-allowed !important;
		/* #endif */
	}
</style>
